在 Elixir 裡也有類似其他語言的字典或雜湊表
%{
"name" => "Jack",
"age" => 33
}
當需要增減或是修改 map 的項目時,
每次更動都會產生一個新的 map,
Elixir 在這部分有基於這個特性的記憶體優化 (結構共享),
但我們並不需要擔心這一部分,只要記得每次改動都是新的 map 即可
常用操作 map 的函式都在 Map 模組 內
# 定義 map
%{} # 可以建立空 map
# 任何值都可以當 key 與 value
%{3 => 4.4}
%{%{3 => 4} => 5}
# 常用 Map.get 取值
Map.get(%{}, "a")
#=> nil
Map.get(%{"a" => 1}, "a")
#=> 1
# 也可以用中括號取值
%{"a" => 1}["a"] #=> 1
# 可以用 Map.put 回傳一個加入新 key value 的 map
# 原本的不會改變
a = %{"name" => "Ann"}
b = Map.put(a, "age", 33)
b #=> %{"age" => 33, "name" => "Ann"} # 新的
a #=> %{"name" => "Ann"} # 舊的
在所有的 key 都是 atom 的時候 (非常常用)
可以使用 :
簡寫
%{:name => "Jack"}
# 等同於
%{name: "jack"}
在這個情況的 map 可以用 .
來取值
profile = %{name: "Jack", age: 23}
profile.name #=> "Jack"
profile.age #=> 23
# 不過這個方法不能取沒有的 key
%{d: 3}.f
(KeyError) key :f not found in: %{d: 3}
這樣寫不行
profile = %{name: "Ken", age: 33}
profile[:age] = 55 # error
對於 Elixir 來說 profile[:age] = 55
這一段是 pattern matching
等同於 33 = 55
導致程式報錯
應改成以下幾種寫法之一
profile = %{name: "Ken", age: 33}
profile = Map.put(profile, :age, 33) # 不管 profile 有沒有 age 都直接取代
profile = Map.replace(profile, :age, 33) # 只要 profile 有 age 就取代
Map 在 pattern matching 的時候有點像篩子
%{"⭐️" => n} = %{"⭐️" => 3, "🌛" => 3, "🌞" => 4}
n #=> 3
也可以一次拿多個
profile = %{name: "Ann", age: 32, mail: "ann@ma.il", mood: "Good"}
%{name: name, mood: mood} = profile
name #=> "Ann"
mood #=> "Good"
既然是 pattern matching 當然要在 case 用用看
case profile do
%{name: "Jack"} -> "只有 name 是 Jack 的會匹配到這行"
%{age: age} when age < 9 -> "匹配出 age 再判斷"
%{name: n, mood: m} when n == m -> "name 跟 mood 的值一樣才會匹配"
%{name: x, mood: x} -> "上一行其實可以寫這樣,直接匹配兩個欄位為 x"
%{} -> "只要 profile 是 map 就會匹配"
_ -> "上面的都沒匹配才會到這"
end
Tuple 是用來用來表示具有固定結構的小型資料組合
在 Elixir 中常用在
{:ok, data}
, {:error, reason}
{:ok, 33}
{x, y} = {22.3, -73}
{r, g, b} = {255, 255, 255}
在 Elixir 社群,套件都有共識的使用 {:ok, “回傳值"}
來代表沒有異常的回傳結果
尤其是 http 要求的套件,檔案的讀取等有機會有例外的行為,就會使用{:ok, 資料}
與 :error
或 {:error, 原因}
這種模式來讓使用者方便處理
我們可以用 pattern matching 來處理這些例外
舉剛剛使用的 Map 模組的函式中的 Map.fetch
profile = %{name: "Tim"}
case Map.fetch(profile) do
{:ok, name} -> name
:error -> "沒有 name"
end